namespace Guia.Elements
{
    using System;
    using System.Reflection;
    using System.Windows.Automation;
    using Guia.Core;

    /// <summary>
    /// This class represents a custom Window.
    /// </summary>
    public class WindowControl : RunnableUiElement, IWindow
    {
        /// <summary>
        /// A dummy Window instance which provides the propper functionality for this WindowControl.
        /// </summary>
        private readonly Window dummyWindow;

        /// <summary>
        /// Initializes a new instance of the <see cref="WindowControl"/> class.
        /// </summary>
        /// <param name="automationElement">The AutomationElement</param>
        public WindowControl(AutomationElement automationElement) : base(automationElement)
        {
            this.dummyWindow = new Window(automationElement);
        }

        /// <summary>
        /// Starts WindowControl with the given Window-type.
        /// </summary>
        /// <typeparam name="T">The type of the concrete Window.</typeparam>
        /// <param name="constructorParameters">The (optional) parameters for initializing the Window.</param>
        /// <returns>The started WindowControl</returns>
        public static WindowControl Start<T>(params object[] constructorParameters) where T : System.Windows.Window
        {
            Type windowType = typeof(T);
            ConstructorInfo constructorInfo = GetConstructorInfo(windowType, constructorParameters);
            return Start<WindowControl>(() => (System.Windows.Window)constructorInfo.Invoke(constructorParameters));
        }

        #region IWindow Members

        /// <summary>
        /// Gets the open MessageBox instance with the given name as title.
        /// </summary>
        /// <param name="name">The name of the MessageBox.</param>
        /// <returns>The MessageBox with the given title.</returns>
        public MessageBox GetMessageBox(string name)
        {
            return this.dummyWindow.GetMessageBox(name);
        }

        /// <summary>
        /// Gets the SaveFileDialog instance of this window with the given name as title.
        /// </summary>
        /// <param name="name">The name of the SaveFileDialog.</param>
        /// <returns>The SaveFileDialog with the given title.</returns>
        public SaveFileDialog GetSaveFileDialog(string name)
        {
            return this.dummyWindow.GetSaveFileDialog(name);
        }

        /// <summary>
        /// Gets the SaveFileDialog of this window with the default-title.
        /// </summary>
        /// <returns>The default-titled SaveFileDialog.</returns>
        public SaveFileDialog GetSaveFileDialog()
        {
            return this.dummyWindow.GetSaveFileDialog();
        }

        /// <summary>
        /// Gets the OpenFileDialog instance of this window with the given name as title.
        /// </summary>
        /// <param name="name">The name of the OpenFileDialog.</param>
        /// <returns>The OpenFileDialog with the given title.</returns>
        public OpenFileDialog GetOpenFileDialog(string name)
        {
            return this.dummyWindow.GetOpenFileDialog(name);
        }

        /// <summary>
        /// Gets the OpenFileDialog of this window with the default-title.
        /// </summary>
        /// <returns>The default-titled OpenFileDialog.</returns>
        public OpenFileDialog GetOpenFileDialog()
        {
            return this.dummyWindow.GetOpenFileDialog();
        }

        /// <summary>
        /// Maximizes the window.
        /// </summary>
        /// <exception cref="OperationNotSupportedException">If maximizing is not supported in the current context.</exception> 
        public void Maximize()
        {
            this.dummyWindow.Maximize();
        }

        /// <summary>
        /// Closes the window.
        /// </summary>
        public void Close()
        {
            this.dummyWindow.Close();
        }

        /// <summary>
        /// Minimizes the window.
        /// </summary>
        /// <exception cref="OperationNotSupportedException">If minimizing is not supported in the current context.</exception> 
        public void Minimize()
        {
            this.dummyWindow.Minimize();
        }

        /// <summary>
        /// Recovers the normal window-size. 
        /// </summary>
        public void RecoverNormal()
        {
            this.dummyWindow.RecoverNormal();
        }

        /// <summary>
        /// Get the window's visual state.
        /// </summary>
        /// <returns>The current visual state of the window</returns>
        public WindowVisualState GetVisualState()
        {
            return this.dummyWindow.GetVisualState();
        }

        /// <summary>
        /// Get the menu with the given automationId.
        /// </summary>
        /// <param name="automationId">The automationId of the desired Menu</param>
        /// <returns>A Menu instance.</returns>
        public Menu GetMenu(string automationId)
        {
            return this.dummyWindow.GetMenu(automationId);
        }

        #endregion

        /// <summary>
        /// This method is executed, before the Runnable entity is being stopped.
        /// It can contain functionality which stopps modal-windows.
        /// </summary>
        protected override void CloseOpenElements()
        {
            Window[] windows = this.GetAll<Window>();
            do
            {
                foreach (Window w in windows)
                {
                    try
                    {
                        w.Close();
                    }
                    catch (OperationNotSupportedException)
                    {
                        // not critical
                    }
                }
            }
            while ((windows = this.GetAll<Window>()).Length > 0);
        }
    }
}